using System;
using System.Linq;
using System.Management;

namespace TripleA.Core.Extensions.WindowsService
{
    /// <summary>
    /// This asserts the windows service has the expected startmode
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class WindowsServiceWmiStepBase<T> : WindowsServiceStepBase<T>
    {
        public class ServiceInfo
        {
            public string Name { get; set; }
            public string DisplayName { get; set; }
            public string StartMode { get; set; }
            public string Identity { get; set; }
            public ManagementObject Properties { get; set; }
        }

        public override void Execute(T context)
        {
            // http://wolfpack.codeplex.com/SourceControl/changeset/view/b9960da6d8cc#Solutions%2fWolfpack.Core%2fChecks%2fWindowsServiceStartupCheck.cs

            var server = string.IsNullOrEmpty(Machine) ? "." : Machine;
            var wmiNamespace = string.Format(@"\\{0}\root\cimv2", server);
            var wmiScope = new ManagementScope(wmiNamespace, new ConnectionOptions
                                                                 {
                                                                     Impersonation = ImpersonationLevel.Impersonate
                                                                 });

            // set up the query and execute it
            var wmiQuery = new ObjectQuery("Select * from Win32_Service");
            var wmiSearcher = new ManagementObjectSearcher(wmiScope, wmiQuery);
            var wmiResults = wmiSearcher.Get();
            var results = wmiResults.Cast<ManagementObject>();
            var service = results.Select(mo => new ServiceInfo
                                                 {
                                                     Name = mo["Name"].ToString(),
                                                     DisplayName = mo["DisplayName"].ToString(),
                                                     StartMode = mo["StartMode"].ToString(),
                                                     Identity = mo["StartName"].ToString(),
                                                     Properties = mo
                                                 })
                .FirstOrDefault(svc => MatchName(ServiceName, svc.Name, svc.DisplayName));

            if (service == null)
                throw new ApplicationException(string.Format("Service '{0}' on '{1}' does not exist", ServiceName, Machine));

            InspectService(service);
        }

        protected abstract void InspectService(ServiceInfo service);

        protected virtual bool MatchName(string requiredService, string name, string displayName)
        {
            return (string.Compare(requiredService, name, StringComparison.OrdinalIgnoreCase) == 0) ||
                   (string.Compare(requiredService, displayName, StringComparison.OrdinalIgnoreCase) == 0);
        }
    }
}